﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace FFmpeg_Joiner
{
    public partial class Form1 : Form
    {
        #region 定义
        public const int WM_SYSCOMMAND = 274;
        public const int SC_MOVE = 61456;
        public const int HTCAPTION = 2;

        private const int Guying_HTLEFT = 10;
        private const int Guying_HTRIGHT = 11;
        private const int Guying_HTTOP = 12;
        private const int Guying_HTTOPLEFT = 13;
        private const int Guying_HTTOPRIGHT = 14;
        private const int Guying_HTBOTTOM = 15;
        private const int Guying_HTBOTTOMLEFT = 16;
        private const int Guying_HTBOTTOMRIGHT = 17;

        public delegate void DelReadErrOutput(string result);
        public delegate void DelReadStdOutput(string result);

        public event DelReadStdOutput ReadStdOutput;
        public event DelReadErrOutput ReadErrOutput;

        [DllImport("user32.dll")]
        public static extern bool ReleaseCapture();

        [DllImport("user32.dll")]
        public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);
        #endregion

        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams createParams = base.CreateParams;
                createParams.Style |= 131072;
                return createParams;
            }
        }

        #region 鼠标移动窗口，两种方法均可实现
        protected override void WndProc(ref Message m)
        {
            int msg = m.Msg;
            if (msg != 132) // 鼠标的移动消息（包括非窗口的移动）
            {
                if (msg == 513) //按下鼠标左键
                {
                    m.Msg = 161; //当光标在一个窗口的非客户区同时按下鼠标左键时提交此消息
                    m.LParam = IntPtr.Zero;
                    m.WParam = new IntPtr(2);
                    base.WndProc(ref m);
                    return;
                }
                base.WndProc(ref m);
            }
            else
            {
                base.WndProc(ref m);
                Point p = new Point((int)m.LParam & 65535, (int)m.LParam >> Guying_HTBOTTOMLEFT & 65535);
                p = base.PointToClient(p);
                if (p.X <= 5)
                {
                    if (p.Y <= 5)
                    {
                        m.Result = (IntPtr)Guying_HTTOPLEFT;
                        return;
                    }
                    if (p.Y >= base.ClientSize.Height - 5)
                    {
                        m.Result = (IntPtr)Guying_HTBOTTOMLEFT;
                        return;
                    }
                    m.Result = (IntPtr)Guying_HTLEFT;
                    return;
                }
                else if (p.X >= base.ClientSize.Width - 5)
                {
                    if (p.Y <= 5)
                    {
                        m.Result = (IntPtr)Guying_HTTOPRIGHT;
                        return;
                    }
                    if (p.Y >= base.ClientSize.Height - 5)
                    {
                        m.Result = (IntPtr)Guying_HTBOTTOMRIGHT;
                        return;
                    }
                    m.Result = (IntPtr)Guying_HTRIGHT;
                    return;
                }
                else
                {
                    if (p.Y <= 5)
                    {
                        m.Result = (IntPtr)Guying_HTTOP;
                        return;
                    }
                    if (p.Y >= base.ClientSize.Height - 5)
                    {
                        m.Result = (IntPtr)Guying_HTBOTTOM;
                        return;
                    }
                }
            }
        }

        private void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            Form1.ReleaseCapture();
            Form1.SendMessage(base.Handle, 274, 61458, 0);
        }
        #endregion

        public Form1()
        {
            this.InitializeComponent();

            this.ReadStdOutput += this.ReadStdOutputAction;
            this.ReadErrOutput += this.ReadErrOutputAction;
        }

        private void ReadStdOutputAction(string result)
        {
            this.Information.AppendText(result + "\r\n");
        }

        private void ReadErrOutputAction(string result)
        {
            this.Information.AppendText(result + "\r\n");
        }

        #region 其他事件
        private void Form1_Load(object sender, EventArgs e)
        {
            if (!File.Exists("ffmpeg.exe"))
            {
                MessageBox.Show("没有找到ffmpeg.exe", "错误", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                base.Dispose();
                Application.Exit();
            }
            if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length > 1)
            {
                MessageBox.Show("已运行程序！", "错误", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                base.Dispose();
                Application.Exit();
            }
        }

        private void AddFile_Click(object sender, EventArgs e)
        {
            openFileDialog1.Multiselect = true;
            openFileDialog1.Title = "请选择文件";
            openFileDialog1.Filter = "视频文件|*.avi;*.wmv;*.wmp;*.wm;*.asf;*.mpg;*.mpeg;*.mpe;*.m1v;*.m2v;*.mpv2;*.mp2v;*.ts;*.tp;*.tpr;*.trp;*.vob;*.ifo;*.ogm;*.ogv;*.mp4;*.m4v;*.m4p;*.m4b;*.3gp;*.3gpp;*.3g2;*.3gp2;*.mkv;*.rm;*.ram;*.rmvb;*.rpm;*.flv;*.swf;*.mov;*.qt;*.amr;*.nsv;*.dpg;*.m2ts;*.m2t;*.mts;*.dvr-ms;*.k3g;*.skm;*.evo;*.nsr;*.amv;*.divx;*.webm;*.wtv;*.f4v";
            openFileDialog1.FilterIndex = 1;
            openFileDialog1.RestoreDirectory = true;
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                this.OpenPath.Text = openFileDialog1.FileName.Substring(0, openFileDialog1.FileName.LastIndexOf("\\"));
                foreach (string item in openFileDialog1.FileNames)
                {
                    this.filelist.Items.Add(item);
                }
            }
        }

        private void Sort_Click(object sender, EventArgs e)
        {
            this.filelist.Sorted = true;
        }

        private void Clear_Click(object sender, EventArgs e)
        {
            this.filelist.Items.Clear();
        }
        #endregion

        #region 拖曳文件
        private void filelist_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.All;
        }

        private void filelist_DragOver(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.All;
        }

        private void filelist_DragDrop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop, false))
            {
                string[] array = (string[])e.Data.GetData(DataFormats.FileDrop);
                int startIndex = array[0].LastIndexOf('.') + 1;
                string a = array[0].Substring(startIndex);
                if (a == "m3u8" || a == "mkv" || a == "avi" || a == "mp4" || a == "ts" || a == "flv" || a == "f4v" || a == "wmv" || a == "wm" || a == "mpeg" || a == "mpg" || a == "m4v" || a == "3gp" || a == "rm" || a == "rmvb" || a == "mov" || a == "qt" || a == "m2ts" || a == "m3u" || a == "mts" || a == "txt")
                {
                    foreach (string item in (string[])e.Data.GetData(DataFormats.FileDrop))
                    {
                        (sender as ListBox).Items.Add(item);
                    }
                }
            }
        }
        #endregion

        #region 最小、最大、退出
        private void button_MIN_Click(object sender, EventArgs e)
        {
            base.WindowState = FormWindowState.Minimized;
        }

        private void button_MAX_Click(object sender, EventArgs e)
        {
            if (this.button_MAX.Text == "FULL")
            {
                base.WindowState = FormWindowState.Maximized;
                this.button_MAX.Text = "NORM";
                return;
            }
            if (this.button_MAX.Text == "NORM")
            {
                base.WindowState = FormWindowState.Normal;
                this.button_MAX.Text = "FULL";
            }
        }

        private void button_EXIT_Click(object sender, EventArgs e)
        {
            base.Dispose();
            Application.Exit();
        }
        #endregion

        private void Notice1_MouseDown(object sender, MouseEventArgs e)
        {
            Form1.ReleaseCapture();
            Form1.SendMessage(base.Handle, 274, 61458, 0);
        }

        private void Information_TextChanged(object sender, EventArgs e)
        {
            if (this.Information.GetLineFromCharIndex(this.Information.TextLength) + 1 > Guying_HTLEFT)
            {
                this.Information.ScrollBars = ScrollBars.Vertical;
            }
            if (this.Information.GetLineFromCharIndex(this.Information.TextLength) + 1 <= Guying_HTLEFT)
            {
                this.Information.ScrollBars = ScrollBars.None;
            }
        }

        private void label2_MouseDown(object sender, MouseEventArgs e)
        {
            Form1.ReleaseCapture();
            Form1.SendMessage(base.Handle, 274, 61458, 0);
        }

        #region 合并视频
        private void FFmpeg_Join_Click(object sender, EventArgs e)
        {
            if (this.filelist.Items.Count == 0)
            {
                MessageBox.Show("没有数据！", "错误", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                return;
            }
            //SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog1.Title = "保存到哪里";
            saveFileDialog1.InitialDirectory = this.OpenPath.Text;
            saveFileDialog1.FileName = "Join";
            saveFileDialog1.Filter = "MKV文件|*.mkv|MP4文件|*.mp4|TS文件|*.ts|FLV文件|*.flv|MOV文件|*.mov";
            saveFileDialog1.FilterIndex = 1;
            saveFileDialog1.RestoreDirectory = true;
            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                this.SaveLstToTxt();
                this.OutPath.Text = saveFileDialog1.FileName;
                this.OutExtendName.Text = saveFileDialog1.FileName.Substring(saveFileDialog1.FileName.LastIndexOf(".") + 1);
                this.Information.Text = "";
                if (this.OutExtendName.Text == "mkv" || this.OutExtendName.Text == "mp4" || this.OutExtendName.Text == "mov")
                {
                    this.Command.Text = "-f concat -safe 0 -i filelist.txt -c copy -bsf:a aac_adtstoasc -threads 0 \"" + this.OutPath.Text + "\"";
                    this.RealAction("ffmpeg.exe", this.Command.Text);
                }
                if (this.OutExtendName.Text == "ts")
                {
                    this.Command.Text = "-f concat -safe 0 -i filelist.txt -c copy -f mpegts -threads 0 \"" + this.OutPath.Text + "\"";
                    this.RealAction("ffmpeg.exe", this.Command.Text);
                }
            }
        }

        private void RealAction(string StartFileName, string StartFileArg)
        {
            Process process = new Process();
            process.StartInfo.FileName = StartFileName;
            process.StartInfo.Arguments = StartFileArg;
            process.StartInfo.CreateNoWindow = true;
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.RedirectStandardInput = true;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.RedirectStandardError = true;
            process.OutputDataReceived += this.p_OutputDataReceived;
            process.ErrorDataReceived += this.p_ErrorDataReceived;
            process.EnableRaisingEvents = true;
            process.Exited += this.CmdProcess_Exited;
            process.Start();
            process.BeginOutputReadLine();
            process.BeginErrorReadLine();
        }

        private void SaveLstToTxt()
        {
            StreamWriter streamWriter = new StreamWriter("filelist.txt", false);
            for (int i = 0; i < this.filelist.Items.Count; i++)
            {
                streamWriter.Write("file '" + this.filelist.Items[i].ToString() + "'\r\n");
            }
            streamWriter.Close();
        }

        private void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (e.Data != null)
            {
                base.Invoke(this.ReadStdOutput, new object[]
                {
                    e.Data
                });
            }
        }

        private void p_ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (e.Data != null)
            {
                base.Invoke(this.ReadErrOutput, new object[]
                {
                    e.Data
                });
            }
        }

        private void CmdProcess_Exited(object sender, EventArgs e)
        {
            MessageBox.Show("合并结束！", "FFmpeg Joiner", MessageBoxButtons.OK, MessageBoxIcon.Asterisk, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);
        }
        #endregion
    }
}
